関数に対するContravariantを実装する
(引き続き)Category Theory for Programmerで提示された Reader (関数)に対する ContravariantをScalaで実装してみました。
はじめに
引き続き今回はContravariantをやっていきます。
Readerに対するFunctor
次のような2つの型パラメータをとる型コンストラクタReaderを考えたとき、そのFunctorの実装は以下のようになります。
タプルやEitherは2つの型パラメータを入れ替えても関手性が成り立ちますが、Readerではどうでしょう?関数の向きを反転したOpを考えたときReaderに対するFunctorは定義できますがOpに対しては定義できません。
import cats.{Functor, Contravariant} package object chap8: type Reader[R, A] = R => A type Op[R, A] = A => R given readerOpFunctor[R]: Functor[Op[R, *]] with def map[A, B](fa: Op[R, A])(f: A => B): Op[R, B] = ??? given readerFunctor[R]: Functor[Reader[R, *]] with def map[A, B](fa: Reader[R, A])(f: A => B): Reader[R, B] = f compose fa
ここでOpに対するContravariant Functor の実装は以下のようになります。
given readerOpContravariant[R]: Contravariant[Op[R, *]] with def contramap[A, B](fa: Op[R, A])(f: B => A): Op[R, B] = fa compose f
Law testing
ReaderおよびOpに対するEqが定義できなかったので今回はありません……
まとめ
Readerの(Covariant) FunctorとOpのContravariantの実装が対称になっているのが双対圏における射の向きと同じになっているのが印象的でした。